home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / KERNEL / ITIMER.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  4KB  |  174 lines

  1. /*
  2.  * linux/kernel/itimer.c
  3.  *
  4.  * Copyright (C) 1992 Darren Senn
  5.  */
  6.  
  7. /* These are all the functions necessary to implement itimers */
  8.  
  9. #include <linux/mm.h>
  10. #include <linux/smp_lock.h>
  11. #include <linux/interrupt.h>
  12.  
  13. #include <asm/uaccess.h>
  14.  
  15. /*
  16.  * change timeval to jiffies, trying to avoid the 
  17.  * most obvious overflows..
  18.  *
  19.  * The tv_*sec values are signed, but nothing seems to 
  20.  * indicate whether we really should use them as signed values
  21.  * when doing itimers. POSIX doesn't mention this (but if
  22.  * alarm() uses itimers without checking, we have to use unsigned
  23.  * arithmetic).
  24.  */
  25. static unsigned long tvtojiffies(struct timeval *value)
  26. {
  27.     unsigned long sec = (unsigned) value->tv_sec;
  28.     unsigned long usec = (unsigned) value->tv_usec;
  29.  
  30.     if (sec > (ULONG_MAX / HZ))
  31.         return ULONG_MAX;
  32.     usec += 1000000 / HZ - 1;
  33.     usec /= 1000000 / HZ;
  34.     return HZ*sec+usec;
  35. }
  36.  
  37. static void jiffiestotv(unsigned long jiffies, struct timeval *value)
  38. {
  39.     value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
  40.     value->tv_sec = jiffies / HZ;
  41. }
  42.  
  43. int do_getitimer(int which, struct itimerval *value)
  44. {
  45.     register unsigned long val, interval;
  46.  
  47.     switch (which) {
  48.     case ITIMER_REAL:
  49.         interval = current->it_real_incr;
  50.         val = 0;
  51.         start_bh_atomic();
  52.         if (timer_pending(¤t->real_timer)) {
  53.             val = current->real_timer.expires - jiffies;
  54.  
  55.             /* look out for negative/zero itimer.. */
  56.             if ((long) val <= 0)
  57.                 val = 1;
  58.         }
  59.         end_bh_atomic();
  60.         break;
  61.     case ITIMER_VIRTUAL:
  62.         val = current->it_virt_value;
  63.         interval = current->it_virt_incr;
  64.         break;
  65.     case ITIMER_PROF:
  66.         val = current->it_prof_value;
  67.         interval = current->it_prof_incr;
  68.         break;
  69.     default:
  70.         return(-EINVAL);
  71.     }
  72.     jiffiestotv(val, &value->it_value);
  73.     jiffiestotv(interval, &value->it_interval);
  74.     return 0;
  75. }
  76.  
  77. /* SMP: Only we modify our itimer values. */
  78. asmlinkage int sys_getitimer(int which, struct itimerval *value)
  79. {
  80.     int error = -EFAULT;
  81.     struct itimerval get_buffer;
  82.  
  83.     if (value) {
  84.         error = do_getitimer(which, &get_buffer);
  85.         if (!error &&
  86.             copy_to_user(value, &get_buffer, sizeof(get_buffer)))
  87.             error = -EFAULT;
  88.     }
  89.     return error;
  90. }
  91.  
  92. void it_real_fn(unsigned long __data)
  93. {
  94.     struct task_struct * p = (struct task_struct *) __data;
  95.     unsigned long interval;
  96.  
  97.     send_sig(SIGALRM, p, 1);
  98.     interval = p->it_real_incr;
  99.     if (interval) {
  100.         if (interval > (unsigned long) LONG_MAX)
  101.             interval = LONG_MAX;
  102.         p->real_timer.expires = jiffies + interval;
  103.         add_timer(&p->real_timer);
  104.     }
  105. }
  106.  
  107. int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
  108. {
  109.     register unsigned long i, j;
  110.     int k;
  111.  
  112.     i = tvtojiffies(&value->it_interval);
  113.     j = tvtojiffies(&value->it_value);
  114.     if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
  115.         return k;
  116.     switch (which) {
  117.         case ITIMER_REAL:
  118.             start_bh_atomic();
  119.             del_timer(¤t->real_timer);
  120.             end_bh_atomic();
  121.             current->it_real_value = j;
  122.             current->it_real_incr = i;
  123.             if (!j)
  124.                 break;
  125.             if (j > (unsigned long) LONG_MAX)
  126.                 j = LONG_MAX;
  127.             i = j + jiffies;
  128.             current->real_timer.expires = i;
  129.             add_timer(¤t->real_timer);
  130.             break;
  131.         case ITIMER_VIRTUAL:
  132.             if (j)
  133.                 j++;
  134.             current->it_virt_value = j;
  135.             current->it_virt_incr = i;
  136.             break;
  137.         case ITIMER_PROF:
  138.             if (j)
  139.                 j++;
  140.             current->it_prof_value = j;
  141.             current->it_prof_incr = i;
  142.             break;
  143.         default:
  144.             return -EINVAL;
  145.     }
  146.     return 0;
  147. }
  148.  
  149. /* SMP: Again, only we play with our itimers, and signals are SMP safe
  150.  *      now so that is not an issue at all anymore.
  151.  */
  152. asmlinkage int sys_setitimer(int which, struct itimerval *value,
  153.                  struct itimerval *ovalue)
  154. {
  155.     struct itimerval set_buffer, get_buffer;
  156.     int error;
  157.  
  158.     if (value) {
  159.         if(verify_area(VERIFY_READ, value, sizeof(*value)))
  160.             return -EFAULT;
  161.         if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
  162.             return -EFAULT;
  163.     } else
  164.         memset((char *) &set_buffer, 0, sizeof(set_buffer));
  165.  
  166.     error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
  167.     if (error || !ovalue)
  168.         return error;
  169.  
  170.     if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
  171.         return -EFAULT; 
  172.     return 0;
  173. }
  174.